package com.mapbased.cc;

import java.io.*;
import javax.servlet.http.*;

import com.mapbased.wfw.*;
import com.mapbased.wfw.handler.*;

/**
 * <p>Title: </p>
 *
 * <p>Description: 并没有真正的缓存对象,只是查询并添加对象的最后修改日期.
 * 当有前段缓存硬件时,这种方式很有用的,另外,这种方式不占用多余的内存,并可有效的节省带宽
 *
 * 使用方式:
 *在url后面加上?local=@cookie{local},以避免多语言环境下缓存key的冲突问题。
 * 参考：News，站点新闻的实现
 * </p>
 *
 * <p>Copyright: Copyright (c) 2006</p>
 *
 * <p>Company: mapbased.com</p>
 *
 * @author chy_hs(Baily)
 * @version 1.0
 */
public   class CacheHelper
    implements HttpConstants
{
    public static interface LastModifyGetter
    {
            long getLastModified(RenderContext rc);

    }
    /**
     * value inseconds.主要控制多久可以不用发请求到服务器,如果知道网页的内容不会变
     * ,可以设一个非常大的值
     *
     * 若小于0，每次都要到服务器确认更新
     * 若==0,使用默认的1个小时
     */
    protected int updateInterval=0;
    protected boolean redirectLocale=true;

    LastModifyGetter lmg;
    public void setLastModifyGetter(LastModifyGetter lmg)
    {
        this.lmg=lmg;
    }

    /**
     * when the request object last modified?
     * 取得请求内容的最后修改时间.
     * 如果带有请求参数,可能需要查询数据库取得对象.这时可以缓存起来,
     * defaultAction中就不用再取了
     * @param rc RenderContext
     * @return long
     */
    public   long getLastModified(RenderContext rc)
    {
            return this.lmg.getLastModified(rc);

    }

    public int getUpdateInterval()
    {
        return this.updateInterval;
    }

    public boolean isRedirectLocale()
    {
        return redirectLocale;
    }

    public void setUpdateInterval(int updateInterval)
    {
        this.updateInterval=updateInterval;
    }

    public void setRedirectLocale(boolean redirectLocale)
    {
        this.redirectLocale=redirectLocale;
    }

    /**
     * 单独拿出来 因为：如果在处理defaultaction 时出错了，可以不加上时间戳，从而不被缓存
     * @param ctx RenderContext
     * @param m long
     */
    public void addTimeHeader(RenderContext ctx,long m)
    {
        HttpServletResponse response=ctx.getResponse();
        if(this.updateInterval >= 0)
        {

            long v=(updateInterval == 0 ? 60L * 60000L :
                                    updateInterval * 1000L);
            response.setDateHeader(this.__Expires,
                                   System.currentTimeMillis() +
                                   v);
            response.setHeader(this.__CacheControl,"max-age="+v/1000L);

        }
        response.setDateHeader(this.__LastModified,m);

    }

    public static void throwIfNeedRedirect(RenderContext rc)
    {
        if(rc.getSureSingleParam("_l").equals(""))
        {
            HttpServletRequest req=rc.getRequest();

            String query=req.getQueryString();
            String np;
            //use configed webroot but not getRequestURL because using squid
            StringBuffer sb=new StringBuffer(rc.getConfig().getValue("webroot"))
                .append(req.getServletPath());
            if(query == null)
            {
                np=sb.append("?_l=").append(rc.getLocale()).
                    toString();
            }
            else
            {

                np=sb.append("?")
                    .append(query)
                    .append("&_l=")
                    .append(rc.getLocale()).toString();
            }

            throw new com.mapbased.wfw.PageRedirectExceprion(np,false);

        }
    }

    /**
     *
     * @param ctx RenderContext
     * @return long :last modifytime
     */
    public long filterRequest(RenderContext ctx)
    {

        HttpServletRequest req=ctx.getRequest();
        if(this.isRedirectLocale())
        {
            throwIfNeedRedirect(ctx);
        }
        long l=req.getDateHeader(this.__IfModifiedSince);

        long m=this.getLastModified(ctx);
        boolean modified=((m - l) / 1000L) > 0L||l<=0L;

        if(modified) //   modified ,so regenerate,also include l<=0
        {
            return m;
        }
        else //return unmodified
        {

            throwUnmodified(ctx);
            return 0l;

        }
    }

    public final void throwNotFound(RenderContext ctx)
    {
        ctx.throwNotFound();

    }

    public final void throwUnmodified(RenderContext ctx)
    {

        HttpServletResponse response=ctx.getResponse();
        response.setStatus(this.__304_Not_Modified);
        if(this.updateInterval >= 0L)
        {
            long v=(updateInterval == 0 ? 60L * 60000L :
                                    updateInterval * 1000L);
            response.setDateHeader(this.__Expires,
                                   System.currentTimeMillis() +
                                   v);
            response.setHeader(this.__CacheControl,"max-age="+v/1000L);
        }

        //  response.flushBuffer();
        throw ExitException.INSTANCE;

    }

}
